using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class Bus
    {

        public NodeVector BusNodes;

        int iWidth;

        System.Collections.Generic.List<NodeVector> NodeVectors;
        System.Collections.Generic.Dictionary<string, NodeVector> NodeVectorsByName;

        Component oParentComponent;
        string sBusName;

        int iStartIdx;
        int iEndIdx;

        public Bus(Component poParentComponent, string psName, int piWidth)
        {
            NodeVectors = new System.Collections.Generic.List<NodeVector>();
            NodeVectorsByName = new System.Collections.Generic.Dictionary<string, NodeVector>();
            iWidth = piWidth;
            oParentComponent = poParentComponent;
            sBusName = psName;

            BusNodes = CreateNodeVector("all", piWidth);
            iStartIdx = piWidth - 1;
        }

        public NodeVector CreateNodeVector(string psName, int piWidth)
        {
            string sName = oParentComponent.NewNodeVectorName(sBusName + "_" + psName);
            return oParentComponent.CreateNodeVector(sName, piWidth);
        }

        public NodeVector DefineNodeVector(string psName, int piWidth)
        {
            NodeVector nvNodeVector = CreateNodeVector(psName, piWidth);
            AddNodeVector(nvNodeVector, psName);
            return nvNodeVector;
        }

        public void AddNodeVector(NodeVector poNodeVector, string psName)
        {
            int piPosition = NodeVectors.Count;
            NodeVectors.Add(poNodeVector);

            if (NodeVectorsByName.ContainsKey(psName))
            {
                NodeVectorsByName[psName] = poNodeVector;
            }
            else
            {
                NodeVectorsByName.Add(psName, poNodeVector);
            }

            BusNodes.ConnectSubset(iStartIdx, iStartIdx - poNodeVector.Width + 1, poNodeVector, 0, poNodeVector.Width - 1);
            iStartIdx -= poNodeVector.Width;
        }

        public NodeVector GetNodeVector(string psName)
        {
            if (NodeVectorsByName.ContainsKey(psName))
            {
                return NodeVectorsByName[psName];
            }
            else
                throw new Exception("Node vector named '" + psName + "' does not exist in bus named " + this.Name);
        }

        public NodeVector GetNodeVector(int piPosition)
        {
            if (NodeVectors.Count < piPosition)
            {
                return NodeVectors[piPosition];
            }
            else
                throw new Exception("Node vector positioned at " + piPosition.ToString() + " does not exist in bus named " + this.Name);
        }

        public NodeVector this[string psName]
        {
            get
            {
                return GetNodeVector(psName);
            }
        }

        public string Name
        {
            get { return sBusName; }
        }

      }
}
